package com.wuzao.aop.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/**
 * 日志切面
 */
@Aspect
@Component
@Slf4j
@Order(2)
public class LogAspect {
    @Pointcut("execution(public * com.wuzao.aop.controller.*.*(..))")
    public void webLog(){}

    @Before("webLog()")
    public void deBefore(JoinPoint joinPoint) throws Throwable {
        log.info("@Order(2) @Before 调用目标方法前，可以获取下面参数");

        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 记录下请求内容
        log.info("      URL : " + request.getRequestURL().toString());
        log.info("      HTTP_METHOD : " + request.getMethod());
        log.info("      IP : " + request.getRemoteAddr());
        log.info("      CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("      ARGS : " + Arrays.toString(joinPoint.getArgs()));
        log.info("");

        // 切面产生异常，会被 controller advice 捕获
//        log.info();(1/0);

    }

    // 异常时，不执行
    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 处理完请求，返回内容
        log.info("@Order(2) @AfterReturning方法的返回值 : " + ret);
        log.info("");
    }

    // 目标方法异常时，执行
    @AfterThrowing("webLog()")
    public void throwss(JoinPoint jp){
        log.info("@Order(2) @AfterThrowing 方法异常时执行.....");
    }

    // 不管是抛出异常或者正常退出都会执行
    @After("webLog()")
    public void after(JoinPoint joinPoint){

        log.info("@Order(2) @After 方法最后执行.....");
    }

    //环绕通知,环绕增强，相当于MethodInterceptor
    @Around("webLog()")
    public Object arround(ProceedingJoinPoint pjp) throws Throwable{
        log.info("@Order(2) @Around 方法环绕start.....");
        try {
            Object o =  pjp.proceed();
            log.info("@Order(2) @Around 方法环绕proceed，结果是 :" + o);
            return o;
        } catch (Throwable e) {
            // 如果还往外抛，会被统一的异常处理捕获
//            throw e;

            // 不再往外抛，则正常返回
            log.info("不再往外抛");
            return "发现异常了，不再往外抛";
        }
    }
}